/*
 * Entry.java   2008/07/28
 *
 * Copyright 2008 Web & Zen Multimedia, All rights reserved.
 * Use is subject to license terms.
 */
package it.wzm.lightweightlog;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;


/**
 * This class is the main wrapper for our error or object we want to log, it is basically
 * a java bean with some getter and setter, and several constructor.
 * It is also implementing few other interfaces:
 * <ul>
 * 	<li>Comparable: to compare with other Entries against timestamp</li>
 * 	<li>Serializable: in future relase serializable will have important role
 * </ul>
 * The class also declare XMLAccessorType and XMLType to be used with RemoteDumping
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "entry", namespace = "http://lightweightlogx.wzm.it", propOrder = {
		"timestamp", "message","severity","classname","name"
})
public class Entry extends LightweightlogObject implements Comparable<Entry>, Serializable {
    
	/**
	 * As required by serialization
	 */
	public static final long serialVersionUID=-16539879023467L;
    /**
     * The date when the log has been created
     */
    private final long timestamp;
    /**
     * The message we want to store
     */
    private final String message;
    /**
     * The severity level for this Entry
     */
    private final Severity severity;
    /**
     * The classname of the class which cause the error
     */
    private final String classname;
    /**
     * The name of the Log
     */
    private final String name;

    
    /**
     * Public and no-arg constructor as required by Web services.
     */
    public Entry() {
    	this.name=null;
    	this.severity=null;
    	this.classname=null;
    	this.message=null;
    	this.timestamp=0;
    }
    
    /**
     * Construct an Entry from a given set of parameter
     * @param service if True the tag '<service>' will be added before the message
     * @param severity severity
     * @param classname the class that throw the error
     * @param obj The object to log
     * @param timestamp when this event occurred
     */
    protected Entry(String name, Object obj, Severity severity, String classname,long timestamp) {
        // those should never be verified
        assert(severity != null):"Severity null";
        assert(classname != null):"Severity null";
        
    	this.name=name;
        this.severity=severity;
        this.timestamp=timestamp;
        this.classname=classname;
        
        // check if we pass a null object
        if (obj==null) {
            this.message="null";
        } else {
        	// if we log an exception we need to build it properly...
        	if (obj instanceof Exception) {
        		StringBuilder stackTrace=new StringBuilder();
        		stackTrace.append(((Exception)obj).getMessage() + "\r\n"); 
        		for ( StackTraceElement s : ((Exception)obj).getStackTrace() ) {
        			stackTrace.append("\tat " + s.getMethodName() + "(" + s.getFileName() + ":" + s.getLineNumber() + ")\r\n");
        		}
        		this.message=stackTrace.toString();
        		stackTrace=null; // clearing...
        	} else {
        		this.message=obj.toString();
        	}
        	obj=null; // clearing...
        }
    }
      
    /**
     * Setter for classname
     * @param classname the classname to set
     */
    //public void setClassname(String classname) {
    //    this.classname = classname;
    //}
    
    /**
     * Getter for classname
     * @return classname
     */
    public String getClassname() {
        return classname;
    }
    
    
    /**
     * Build a line of log from the Entry variable example:
     * 2008-07-29 10:22:09 ERROR [it.wzm.common.lightweightlog.client.SampleLog]: err:0
     * @return String
     */
    public String getLine() {
        //return this.line; 
    	return (
		DEFAULT_LINE_DATEFORMAT.format(this.getTimestamp())
        + " "
        + this.getSeverity()
        //+ " - " + this.getName() + " -"
        + " [" + this.getClassname() + "]: "
        + this.getMessage() 
        );            	
    }
    
    /**
     * Getter for timestamp
     * @return timestamp
     */
    public long getTimestamp() {
        return timestamp;
    }
    /**
     * Setter for timestamp
     * @param timestamp when the Entry has been recorded
     */
    //public void setTimestamp(long timestamp) {
      //  this.timestamp = timestamp;
    //}
    
    /**
     * Getter for message
     * @return String
     */
    public String getMessage() {
        return message;
    }
    
    /**
     * Setter for message
     * @param message String
     */
    //public void setMessage(String message) {
      //  this.message = message;
    //}
    
    /**
     * Getter for severity
     * @return Severity
     */
    public Severity getSeverity() {
        return severity;
    }    
    
    /**
     * We decide if an Entry is less then another by comparing each timestamp
     * @param e the Entry to compare
     * @return -1, 0, 1 depending...
     */
    public int compareTo(Entry e) {
    	// no way...
        if (e==null)
        	throw new NullPointerException("Cannot compare to null");
        
        // first comparison is based on the hashcode...
        if (this.hashCode()==e.hashCode()) {
        	return 0;
        }
        //System.out.println(this.getTimestamp() + "==" +  e.getTimestamp());
        // patch for storing Entry in SortedSet...
        // when we found two identical timestamp we also match the hashcode        
        if (this.getTimestamp() == e.getTimestamp()) {
        	if (this.hashCode() > e.hashCode()  ) return 1;
        	else return -1;        	
        }
        // then natural ordering apply... 
        return Double.compare(this.getTimestamp(), e.getTimestamp());
    }
    
    /**
     * Overridding from Object
     */
    @Override
    public String toString() {
    	return this.getClass().getName() + "{hc=" + this.hashCode() + ", message=" + this.getMessage() + "}";
    }

    /**
     * Comparison between two Entry is done against hash code 
     */
    @Override
    public boolean equals(Object o) {
    	if (o instanceof Entry) {
    		if (o.hashCode() == this.hashCode() )
    			return true;
    		else 
    			return false;
    	} else {
    		return true;
    	}
    }
    
}

